package com.jfs.cmd;

import com.jfs.constant.CommonConstant;
import com.jfs.constant.SipConstant;
import com.jfs.observer.request.abstracts.AbstractProcessor;
import com.jfs.properties.SipProperties;

import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.ArrayList;

/**
 * @Description 指令实现者抽象类
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022-08-23
 */
public abstract class AbstractSIPCommander extends AbstractProcessor {
    public AbstractSIPCommander(SipFactory sipFactory, SipProvider tcpSipProvider, SipProvider udpSipProvider, SipProperties sipProperties) {
        super(sipFactory, tcpSipProvider, udpSipProvider, sipProperties);
    }

    /**
     * 创建message 请求
     *
     * @param deviceId     设备id
     * @param content      请求体
     * @param ip           请求地址ip
     * @param transport    请求类型 tcp or udp
     * @param viaTag       via 域标志
     * @param fromTag      服务端发送标志
     * @param toTag        客户端收到标志
     * @param callIdHeader callId 头对象
     * @return
     * @throws ParseException
     * @throws InvalidArgumentException
     * @throws PeerUnavailableException
     */
    public Request createMessageRequest(String deviceId, String content, String ip, Integer port, String transport, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
        // sipuri
        SipURI requestURI = sipFactory.createAddressFactory().createSipURI(deviceId, ip + CommonConstant.COLON + port);
        // via
        ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
        ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipProperties.getMonitorIp(), sipProperties.getPort(), transport, viaTag);
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);
        // from
        SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipProperties.getSipId(),
                sipProperties.getMonitorIp() + CommonConstant.COLON + sipProperties.getPort());
        Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
        FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
        // to
        SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(deviceId, sipProperties.getDomain());
        Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
        ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);

        // Forwards
        MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
        // ceq
        CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);

        Request request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
                toHeader, viaHeaders, maxForwards);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader(SipConstant.CONTENT_TYPE, SipConstant.CONTENT_XML_TYPE);
        request.setContent(content, contentTypeHeader);
        return request;
    }

    /**
     * 创建客户端回话 发送请求
     *
     * @param transport
     * @param request
     * @return
     * @throws SipException
     */
    public ClientTransaction transmitRequest(String transport, Request request) throws SipException {
        ClientTransaction clientTransaction = null;
        if (SipConstant.TRANSPORT_TCP.equals(transport)) {
            clientTransaction = tcpSipProvider.getNewClientTransaction(request);
        } else {
            clientTransaction = udpSipProvider.getNewClientTransaction(request);
        }
        clientTransaction.sendRequest();
        return clientTransaction;
    }


    /**
     * 创建Invite类型请求
     *
     * @param ip
     * @param content
     * @param channelId
     * @param port
     * @param transport
     * @param viaTag
     * @param fromTag
     * @param callIdHeader
     * @param ssrc
     * @return
     * @throws PeerUnavailableException
     * @throws ParseException
     * @throws InvalidArgumentException
     */
    public Request createInviteRequest(String ip, String content, String channelId, Integer port, String transport, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws PeerUnavailableException, ParseException, InvalidArgumentException {
        //请求行
        SipURI requestLine = getAddressFactory().createSipURI(channelId, ip + CommonConstant.COLON + port);
        //via
        ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
        ViaHeader viaHeader = getHeaderFactory().createViaHeader(ip, port, transport, viaTag);
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);
        //from
        SipURI fromSipURI = getAddressFactory().createSipURI(sipProperties.getSipId(), sipProperties.getDomain());
        Address fromAddress = getAddressFactory().createAddress(fromSipURI);
        //必须要有标记，否则无法创建会话，无法回应ack
        FromHeader fromHeader = getHeaderFactory().createFromHeader(fromAddress, fromTag);
        //to
        SipURI toSipURI = getAddressFactory().createSipURI(channelId, sipProperties.getDomain());
        Address toAddress = getAddressFactory().createAddress(toSipURI);
        ToHeader toHeader = getHeaderFactory().createToHeader(toAddress, toTag);
        //Forwards
        MaxForwardsHeader maxForwards = getHeaderFactory().createMaxForwardsHeader(70);
        //ceq
        CSeqHeader cSeqHeader = getHeaderFactory().createCSeqHeader(1L, Request.INVITE);
        Request request = getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
        Address address = getAddressFactory().createAddress(getAddressFactory().createSipURI(sipProperties.getSipId(), sipProperties.getMonitorIp() + CommonConstant.COLON + sipProperties.getPort()));
        request.addHeader(getHeaderFactory().createContactHeader(address));
        // Subject
        SubjectHeader subjectHeader = getHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipProperties.getSipId(), 0));
        request.addHeader(subjectHeader);
        ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader(SipConstant.CONTENT_TYPE, SipConstant.CONTENT_SDP_TYPE);
        request.setContent(content, contentTypeHeader);
        return request;
    }
}
